"""管理进程有os.fork()和multiprocessing模块，
py同时也支持Pool进程池，
但是os.fork()只能在Unix系统上使用，
而multiprocessing模块可以在所有系统上使用。"""
from multiprocessing import Process

#子程序
def test(interval):
    print("传入参数为",interval)

def test_main():
    print("主程序开始")
    p=Process(target=test,args=(1,)) #target是函数名，args是参数，注意args是元组，所以就算传入参数只有一个，也要加一个逗号
    p.start() #启动进程
    p.join() #等待进程结束
    print("主程序结束")

if __name__ == '__main__': #判断该程序是不是主程序，如果是主程序，则执行下面的代码；一般而言，如果是被引用的模块，则不执行下面的代码
    test_main()


#如果传入参数大于1个，则args参数需要用元组传入，例如args=(1,2,3)
def test(interval,i2,i3):
    print("传入参数为",interval,i2,i3)

def test_main():
    print("主程序开始")
    p=Process(target=test,args=(1,2,3)) #target是函数名，args是参数，注意args是元组，所以就算传入参数只有一个，也要加一个逗号
    p.start() #启动进程
    p.join() #等待进程结束
    print("主程序结束")

if __name__ == '__main__': #判断该程序是不是主程序，如果是主程序，则执行下面的代码；一般而言，如果是被引用的模块，则不执行下面的代码
    test_main()


import os
# 可以通过继承重写process类，实现自己的进程类
class MyProcess(Process):
    def __init__(self, interval):
        super().__init__()
        self.interval = interval

    def run(self):
        print("传入参数为",self.interval)
        print("当前pid",os.getpid()) #获取当前进程的pid

def test_main():
    print("主程序开始")
    p1=MyProcess(1) 
    p2=MyProcess(2)
    p1.start() #启动进程
    p2.start()
    p1.join() #等待进程结束
    p2.join() #等待进程结束
    print("主程序结束")

if __name__ == '__main__': #判断该程序是不是主程序，如果是主程序，则执行下面的代码；一般而言，如果是被引用的模块，则不执行下面的代码
    test_main()



#进程池
from multiprocessing import Pool
if __name__ == '__main__': #一定要使用if判断，否则会报错，这是因为子进程会重新导入主模块，如果没有这个保护，可能会导致无限递归创建进程，从而引发错误。
    pool=Pool(processes=10) #创建进程池，进程池中最多有10个进程
    for i in range(10):
        pool.apply_async(func=test,args=(i,)) #func是函数名，args是参数，注意args是元组，所以就算传入参数只有一个，也要加一个逗号
    pool.close() #关闭进程池，不再接受新的进程
    pool.join() #等待进程池中的进程全部执行完毕,必须放在close()之后

#进程池的API
pool = Pool(processes=10)
pool.apply_async(func=test,args=(1,)) #异步方式，也就是非阻塞方式
pool.apply(func=test,args=(2,)) #同步方式，也就是阻塞方式
pool.close() #关闭进程池，不再接受新的进程
pool.join() #等待进程池中的进程全部执行完毕,必须放在close()之后
pool.terminate() #终止进程池中的进程，立即终止，不等待进程池中的进程执行完毕


#队列，适用于进程间的通信
from multiprocessing import Queue
import time

def write_task(q):
    if not q.full():
        for i in range(10):
            q.put(i)
            print("写入任务",i)
            time.sleep(1)

def read_task(q):
    while not q.empty():
        print("读取任务",q.get(True,2)) #如果队列为空，则等待2秒，如果2秒后还是空，则抛出异常
        time.sleep(1)


if __name__ == '__main__':
    # q=Queue(10) #创建队列，最大容量为10
    q=Queue() #创建队列，最大容量为系统默认值
    p1=Process(target=write_task,args=(q,))
    p2=Process(target=read_task,args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print("主程序结束")


#使用threading模块实现多线程，该模块为编译器内置
import threading
def process1(interval):
    print("传入参数为",interval)


if __name__ == '__main__':
    print("主程序开始")
    threads=(threading.Thread(target=process1,args=(1,)) for i in range(10))
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    print("主程序结束")



#也可以通过继承threading.Thread类，实现自己的线程类
class MyThread(threading.Thread):
    def __init__(self, interval):
        super().__init__()
        self.interval = interval

    def run(self):
        print("传入参数为",self.interval)

if __name__ == '__main__':
    print("主程序开始")
    threads=(MyThread(1) for i in range(10))
    for t in threads:
        t.start()



#对于于多线程，可以使用threading模块的Lock类实现线程同步，避免多线程同时操作共享资源导致的错误
from threading import Lock, Thread
import time
lock=Lock()
n=100
def process1(interval):
    global n #声明全局变量
    lock.acquire() #获取锁
    n=n-1
    lock.release() #释放锁
    print(n)

if __name__ == '__main__':
    print("主程序开始")
    threads=(threading.Thread(target=process1,args=(1,)) for i in range(10))
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    print("主程序结束")